using System;
using System.Collections.Generic;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using Opc.Ua;
using Opc.Ua.Server;

namespace HslCommunicationEx.OpcUa.Server
{
	public class PeanutOpcUaServer<T> : StandardServer where T : PeanutOpcUaNodeManager
	{
		private Dictionary<string, string> _dicAdminUserList = new Dictionary<string, string>
		{
			{ "OpcUaClient", "SUNRISE" },
			{ "Administrator", "sunrise@123" }
		};

		private Dictionary<string, string> _dicUserList = new Dictionary<string, string> { { "user", "2357" } };

		private ICertificateValidator m_userCertificateValidator;

		public string NameSpace { get; set; } = "http://opcfoundation.org";


		public Tuple<bool, string> AddUser(string userName, string pwd, bool isSysIdendfy = false)
		{
			if (isSysIdendfy)
			{
				if (!this._dicAdminUserList.ContainsKey(userName))
				{
					this._dicAdminUserList.Add(userName, pwd);
					return new Tuple<bool, string>(item1: true, "");
				}
				if (this._dicAdminUserList.Remove(userName))
				{
					this._dicAdminUserList.Add(userName, pwd);
				}
			}
			else
			{
				if (!this._dicUserList.ContainsKey(userName))
				{
					this._dicUserList.Add(userName, pwd);
					return new Tuple<bool, string>(item1: true, "");
				}
				if (this._dicUserList.Remove(userName))
				{
					this._dicUserList.Add(userName, pwd);
				}
			}
			return new Tuple<bool, string>(item1: false, "add user failed!");
		}

		protected override MasterNodeManager CreateMasterNodeManager(IServerInternal server, ApplicationConfiguration configuration)
		{
			Utils.Trace("Creating the Node Managers.");
			List<INodeManager> list = new List<INodeManager>();
			T item = (T)Activator.CreateInstance(typeof(T), server, configuration, this.NameSpace);
			list.Add(item);
			return new MasterNodeManager(server, configuration, null, list.ToArray());
		}

		protected override ServerProperties LoadServerProperties()
		{
			ServerProperties serverProperties = new ServerProperties();
			serverProperties.ManufacturerName = "OPC Foundation";
			serverProperties.ProductName = "Quickstart Reference Server";
			serverProperties.ProductUri = "http://opcfoundation.org/Quickstart/ReferenceServer/v1.04";
			serverProperties.SoftwareVersion = Utils.GetAssemblySoftwareVersion();
			serverProperties.BuildNumber = Utils.GetAssemblyBuildNumber();
			serverProperties.BuildDate = Utils.GetAssemblyTimestamp();
			return serverProperties;
		}

		protected override ResourceManager CreateResourceManager(IServerInternal server, ApplicationConfiguration configuration)
		{
			ResourceManager resourceManager = new ResourceManager(server, configuration);
			FieldInfo[] fields = typeof(StatusCodes).GetFields(BindingFlags.Static | BindingFlags.Public);
			FieldInfo[] array = fields;
			foreach (FieldInfo fieldInfo in array)
			{
				uint? num = fieldInfo.GetValue(typeof(StatusCodes)) as uint?;
				if (num.HasValue)
				{
					resourceManager.Add(num.Value, "en-US", fieldInfo.Name);
				}
			}
			return resourceManager;
		}

		protected override void OnServerStarting(ApplicationConfiguration configuration)
		{
			Utils.Trace("The server is starting.");
			base.OnServerStarting(configuration);
			this.CreateUserIdentityValidators(configuration);
		}

		protected override void OnServerStarted(IServerInternal server)
		{
			base.OnServerStarted(server);
			server.SessionManager.ImpersonateUser += SessionManager_ImpersonateUser;
			try
			{
				server.Status.Variable.CurrentTime.MinimumSamplingInterval = 250.0;
			}
			catch
			{
			}
		}

		private void CreateUserIdentityValidators(ApplicationConfiguration configuration)
		{
			for (int i = 0; i < configuration.ServerConfiguration.UserTokenPolicies.Count; i++)
			{
				UserTokenPolicy userTokenPolicy = configuration.ServerConfiguration.UserTokenPolicies[i];
				if (userTokenPolicy.TokenType == UserTokenType.Certificate && configuration.SecurityConfiguration.TrustedUserCertificates != null && configuration.SecurityConfiguration.UserIssuerCertificates != null)
				{
					CertificateValidator certificateValidator = new CertificateValidator();
					certificateValidator.Update(configuration.SecurityConfiguration).Wait();
					certificateValidator.Update(configuration.SecurityConfiguration.UserIssuerCertificates, configuration.SecurityConfiguration.TrustedUserCertificates, configuration.SecurityConfiguration.RejectedCertificateStore);
					this.m_userCertificateValidator = certificateValidator.GetChannelValidator();
				}
			}
		}

		private void SessionManager_ImpersonateUser(Session session, ImpersonateEventArgs args)
		{
			UserNameIdentityToken userNameIdentityToken = args.NewIdentity as UserNameIdentityToken;
			if (userNameIdentityToken != null)
			{
				args.Identity = this.VerifyPassword(userNameIdentityToken);
				args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_AuthenticatedUser);
				if (args.Identity is SystemConfigurationIdentity)
				{
					args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_ConfigureAdmin);
					args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_SecurityAdmin);
				}
				return;
			}
			X509IdentityToken x509IdentityToken = args.NewIdentity as X509IdentityToken;
			if (x509IdentityToken != null)
			{
				this.VerifyUserTokenCertificate(x509IdentityToken.Certificate);
				args.Identity = new UserIdentity(x509IdentityToken);
				Utils.Trace("X509 Token Accepted: {0}", args.Identity.DisplayName);
				args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_AuthenticatedUser);
			}
			else
			{
				args.Identity = new UserIdentity();
				args.Identity.GrantedRoleIds.Add(ObjectIds.WellKnownRole_Anonymous);
			}
		}

		private IUserIdentity VerifyPassword(UserNameIdentityToken userNameToken)
		{
			string userName = userNameToken.UserName;
			string decryptedPassword = userNameToken.DecryptedPassword;
			if (string.IsNullOrEmpty(userName))
			{
				throw ServiceResultException.Create(2149580800u, "Security token is not a valid username token. An empty username is not accepted.");
			}
			if (string.IsNullOrEmpty(decryptedPassword))
			{
				throw ServiceResultException.Create(2149646336u, "Security token is not a valid username token. An empty password is not accepted.");
			}
			if (this._dicAdminUserList.ContainsKey(userName) && this._dicAdminUserList[userName] == decryptedPassword)
			{
				return new SystemConfigurationIdentity(new UserIdentity(userNameToken));
			}
			if (this._dicUserList.ContainsKey(userName) && this._dicUserList[userName] == decryptedPassword)
			{
				return new UserIdentity(userNameToken);
			}
			TranslationInfo translationInfo = new TranslationInfo("InvalidPassword", "en-US", "Invalid username or password.", userName);
			throw new ServiceResultException(new ServiceResult(2149515264u, "InvalidPassword", this.LoadServerProperties().ProductUri, new LocalizedText(translationInfo)));
		}

		private void VerifyUserTokenCertificate(X509Certificate2 certificate)
		{
			try
			{
				if (this.m_userCertificateValidator != null)
				{
					this.m_userCertificateValidator.Validate(certificate);
				}
				else
				{
					base.CertificateValidator.Validate(certificate);
				}
			}
			catch (Exception ex)
			{
				StatusCode code = 2149646336u;
				ServiceResultException ex2 = ex as ServiceResultException;
				TranslationInfo translationInfo;
				if (ex2 != null && ex2.StatusCode == 2149056512u)
				{
					translationInfo = new TranslationInfo("InvalidCertificate", "en-US", "'{0}' is an invalid user certificate.", certificate.Subject);
					code = 2149580800u;
				}
				else
				{
					translationInfo = new TranslationInfo("UntrustedCertificate", "en-US", "'{0}' is not a trusted user certificate.", certificate.Subject);
				}
				throw new ServiceResultException(new ServiceResult(code, translationInfo.Key, this.LoadServerProperties().ProductUri, new LocalizedText(translationInfo)));
			}
		}
	}
}
